/***************************************************************************
 *   Copyright (C) 2007, 2008 by Andreas Theofilu                          *
 *   andreas@theosys.at                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation version 3 of the License.                *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef _DISASSEMBLE_H
#define _DISASSEMBLE_H

#define DEG_2_RAD  0.0174532925199432957692369076848861271L

/**
 * \file disassemble.h
 */

typedef struct
{
  int		   type;
  char             ident[7];       /* identifier            */
  position_type    posn;           /* position              */
  char             cmnt[41];       /* comment               */
  float32          dst;            /* proximity distance (meters) */
  uint8            smbl;           /* symbol id                   */
  uint8            dspl;           /* display option                */
  char *           wpt_ident;      /* null-terminated string      */
  char *           lnk_ident;      /* null-terminated string  */
  uint8            wpt_class;      /* class                   */
  unsigned char    subclass[21];   /* subclass                */
  uint8            color;          /* waypoint color               */
  uint8            attr;           /* attributes (see below)          1      */
  float32          alt;            /* altitude in meters              4      */
  float32          dpth;           /* depth in meters                 4      */
  char             state[3];       /* state                           2      */
  char             cc[3];          /* country code                    2      */
  char *           identity;          /* variable length string          1-51   */
  char *           comment;        /* waypoint user comment           1-51   */
  char *           facility;       /* facility name                   1-31   */
  char *           city;           /* city name                       1-25   */
  char *           addr;           /* address number                  1-51   */
  char *           cross_road;     /* intersecting road label         1-51   */
  uint8            dtyp;           /* data packet type (0x01 for D109) 1    */
  uint8            dspl_color;     /* display & color (see below)      1    */
  uint32           ete;            /* outbound link ete in seconds     4    */
  float32          temp;           /* temperature                      4    */
  time_type        time;           /* timestamp                        4    */
  sint16           idx;            /* proximity index                   */
} WAYPOINT;

typedef struct
{
  char             name[18];        /* category name */
} WPCATEGORY;

typedef struct
{
  int		        type;
  uint8                 nmbr;       /* route number            */
  char                  cmnt[21];   /* comment                 */
  char *                rte_ident;  /* null-terminated string  */
} ROUTE;

typedef struct
{
  int			type;
  uint16                klasse;        /* link class; see below           */
  uint8                 subclass[20]; /* sublcass                        */
  char *                ident;        /* variable length string          */
} ROUTE_LINK;

typedef struct
{
  int		    type;
  position_type     posn;      /* position                        */
  uint32            time;      /* time                            */
  bool              new_trk;   /* new track segment?              */
  float32           alt;      /* altitude in meters        */
  float32           dpth;     /* depth in meters           */
  float32           temp;
  uint8             heart_rate;
  float32           distance;
  uint8             cadence;
  bool              sensor;
} POINT;

typedef struct POINT_NODE
{
	int number;
	POINT *point;
	POINT_NODE *next;
} POINT_NODE;

typedef struct
{
  int		type;
  bool          dspl;           /* display on the map?        */
  uint8         color;          /* color (same as D108)       */
  char *        trk_ident;      /* null-terminated string     */
  uint16        index;   /* unique among all tracks received from device */
} TRACK;

typedef struct
{
  int		type;
  sint16        wn;    /* week number                          (weeks)    */
  float32       toa;   /* almanac data reference time              (s)    */
  float32       af0;   /* clock correction coefficient             (s)    */
  float32       af1;   /* clock correction coefficient           (s/s)    */
  float32       e;     /* eccentricity                             (-)    */
  float32       sqrta; /* square root of semi-major axis (a)  (m**1/2)    */
  float32       m0;    /* mean anomaly at reference time           (r)    */
  float32       w;     /* argument of perigee                      (r)    */
  float32       omg0;  /* right ascension                          (r)    */
  float32       odot;  /* rate of right ascension                (r/s)    */
  float32       i;     /* inclination angle                        (r)    */
  uint8         hlth;  /* almanac health                                 */
  char          svid;  /* satellite id                                   */
} ALMANAC;

typedef struct
{
  uint8     month;            /* month  (1-12)                  */
  uint8     day;              /* day    (1-31)                  */
  uint16    year;             /* year   (1990 means 1990)       */
  sint16    hour;             /* hour   (0-23)                  */
  uint8     minute;           /* minute (0-59)                  */
  uint8     second;           /* second (0-59)                  */
} DATETIME;

typedef struct
{
  int		    type;
  time_type         takeoff_time;
  time_type         landing_time;
  position_type     takeoff_posn;
  position_type     landing_posn;
  uint32            night_time;
  uint32            num_landings;
  float32           max_speed;
  float32           max_alt;
  float32           distance;
  bool              cross_country_flag;
  char *            departure_name;
  char *            departure_ident;
  char *            arrival_name;
  char *            arrival_ident;
  char *            ac_id;
} FLIGHTBOOK;

typedef struct
{
  float32               alt;        /* alt above WGS 84 ellipsoid (m)        */
  float32               epe;        /* est. position error, 2 sigma (m)      */
  float32               eph;        /* epe, but horizontal only (meters)     */
  float32               epv;        /* epe, but vertical only (meters)       */
  sint16                fix;        /* type of position fix                  */
  float64               tow;        /* time of week (seconds)                */
  radian_position_type  posn;       /* latitude and longitude (radians)      */
  float32               east;       /* velocity east  (meters/second)        */
  float32               north;      /* velocity north (meters/second)        */
  float32               up;         /* velocity up    (meters/second)        */
  float32               msl_hght;   /* ht. of WGS 84 ellipsoid above MSL (m) */
  sint16                leap_scnds; /* diff between GPS and UTC (seconds)    */
  sint32                wn_days;    /* week number days                      */
} PVT;

typedef struct
{
  int		   type;
  uint32           start_time;
  uint32           total_time;      /* In hundredths of a second */
  float32          total_distance;  /* In meters */
  position_type    begin;           /* Invalid if lat and lon are 0x7fffffff */
  position_type    end;             /* Invalid if lat and lon are 0x7fffffff */
  uint16           calories;
  uint8            track_index;     /* See below */
  uint32           index;
  float32          max_speed;
  uint8            avg_heart_rate;
  uint8            max_heart_rate;
  uint8            intensity;
  uint8            avg_cadence;
  uint8            trigger_method;
} LAP;

typedef struct LAP_NODE
{
	LAP *lap;
	LAP_NODE *next;
} LAP_NODE;

typedef struct
{
  int			       type;
  uint32                       num_valid_steps;
  struct {
    char                       custom_name[17];
    float32                    target_custom_zone_low;
    float32                    target_custom_zone_high;
    uint16                     duration_value;
    uint8                      intensity;
    uint8                      duration_type;
    uint8                      target_type;
    uint8                      target_value;
  }                            steps[20];
  char                         name[17];
  uint8                        sport_type;
  char                         workout_name[17];
  time_type                    day;
  uint32                       max_workouts;
  uint32                       max_unscheduled_workouts;
  uint32                       max_occurrences;
} WORKOUT;

typedef struct
{
  int				type;
  uint32                       track_index;
  uint32                       first_lap_index;
  uint32                       last_lap_index;
  uint8                        sport_type;
  uint8                        program_type;
  uint8                        multisport;
  struct {
    uint32                     time;
    float32                    distance;
  }                            virtual_partner;
  WORKOUT                      workout;
} RUN;

typedef struct RUN_NODE
{
	RUN *run;
	RUN_NODE *next;
} RUN_NODE;

typedef struct
{
  int			       type;
  struct {
    struct {
      uint8                    low_heart_rate;
      uint8                    high_heart_rate;
    }                          heart_rate_zones[5];
    struct {
      float32                  low_speed;
      float32                  high_speed;
      char                     name[17];
    }                          speed_zones[10];
    float32                    gear_weight;
    uint8                      max_heart_rate;
  }                            activities[3];
  float32                      weight;
  uint16                       birth_year;
  uint8                        birth_month;
  uint8                        birth_day;
  uint8                        gender;
} FITNESS;

typedef struct
{
  int				type;
  uint16                       index;
  char                         course_name[17];
  uint16                       track_index;
  uint16                       course_index;
  uint16                       lap_index;
  uint32                       total_time;
  float32                      total_dist;
  position_type                begin;
  position_type                end;
  uint8                        avg_heart_rate;
  uint8                        max_heart_rate;
  uint8                        intensity;
  uint8                        avg_cadence;
  time_type                    track_point_time;
  uint8                        point_type;
  uint32                       max_courses;
  uint32                       max_course_laps;
  uint32                       max_course_pnt;
  uint32                       max_course_trk_pnt;
} COURSE;

/**
  * disassemble provides support for some Garmin Forerunner devices
  * connected over the USB port.
  *
  * It has routines to get out the data structure and stores everything
  * into an own structure. Beside this, it finds out some statistic
  * values.
  *
  * @author Andreas Theofilu <andreas@theosys.at>
  * @short class for deviding Garmin binary data into a structure
  */
class disassemble
{
	public:
	/**
	  * Constructs a disassemble class.
	  */
	   disassemble();
	/**
	  * Destructor
	  */
	   ~disassemble();
	/**
	  * Destroys all stored information about the currently loaded
	  * activity and cleans everything.
	  *
	  * This must be called before a new activity is loaded. It is also
	  * called, when the class is deleted from the destructor.
	  */
	   void destroy();
	/**
	  * This function needs a garmin_data structure. It devides the
	  * raw data in it to a node chain, a chain containing the laps and
	  * a chain containing all points.
	  *
	  * @param d    A pointer to a garmin_data structure.
	  */
	   void garmin_print_data (garmin_data *d);

	   LAP_NODE *addLap ();
	   LAP_NODE *getLapNode () { return lap_node; }
	   LAP *getLap(int index);
	   LAP *getLapT(uint32 time);

	   RUN_NODE *addRun ();
	   RUN_NODE *getRunNode () { return run_node; }

	   POINT_NODE *addPoint();
	   POINT_NODE *getPointNode() { return point_node; }
	   POINT *getPoint(int number);
	   POINT *getPoint(uint32 time);
	   POINT *getLastPoint();

	   double getTotalDistance() { return totalDistance; }
	   long   getTotalTime() { return totalTime; }
	   long   getPauseTime() { return pauseTime; }
	   double getAvgHR() { return avgHR; }
	   double getAvgSpeed() { return avgSpeed; }
	   double getMaxSpeed() { return maxSpeed; }
	   int    getAvgCadence() { return avgCadence; }
	   double getAscend() { return ascend; }
	   double getDescend() { return descend; }

	   double CalcRad(double lat);
	   double earth_distance(double lat1, double lon1, double lat2, double lon2);

	protected:
	   void garmin_print_dlist (garmin_list *l);
	   char *garmin_print_dtime (uint32 t);
	   void garmin_print_dpos (position_type *pos, double *lat, double *lon);
	   char *garmin_print_float32 (float32 f, char *ret);
	   char *garmin_print_float64 (float64 f, char *ret);
	   char *garmin_print_dfloat32 (float32 f, char *ret);
	   char *garmin_print_ddist (uint32 dur, char *ret);

	private:
	   void garmin_print_d100 (D100 *x);
	   void garmin_print_d101 (D101 *x);
	   void garmin_print_d102 (D102 *x);
	   void garmin_print_d103 (D103 *x);
	   void garmin_print_d104 (D104 *x);
	   void garmin_print_d105 (D105 *x);
	   void garmin_print_d106 (D106 *x);
	   void garmin_print_d107 (D107 *x);
	   void garmin_print_d108 (D108 *x);
	   void garmin_print_d109 (D109 *x);
	   void garmin_print_d110 (D110 *x);
	   void garmin_print_d120 (D120 *x);
	   void garmin_print_d150 (D150 *x);
	   void garmin_print_d151 (D151 *x);
	   void garmin_print_d152 (D152 *x);
	   void garmin_print_d154 (D154 *x);
	   void garmin_print_d155 (D155 *x);
	   void garmin_print_d200 (D200 *x);
	   void garmin_print_d201 (D201 *x);
	   void garmin_print_d202 (D202 *x);
	   void garmin_print_d210 (D210 *x);
	   void garmin_print_d300 (D300 *p);
	   void garmin_print_d301 (D301 *p);
	   void garmin_print_d302 (D302 *p);
	   void garmin_print_d303 (D303 *p);
	   void garmin_print_d304 (D304 *p);
	   void garmin_print_d310 (D310 *x);
	   void garmin_print_d311 (D311 *h);
	   void garmin_print_d312 (D312 *h);
	   void garmin_print_d400 (D400 *x);
	   void garmin_print_d403 (D403 *x);
	   void garmin_print_d450 (D450 *x);
	   void garmin_print_d500 (D500 *x);
	   void garmin_print_d501 (D501 *x);
	   void garmin_print_d550 (D550 *x);
	   void garmin_print_d551 (D551 *x);
	   void garmin_print_d600 (D600 *x);
	   void garmin_print_d650 (D650 *x);
	   void garmin_print_d700 (D700 *x);
	   void garmin_print_d800 (D800 *x);
	   void garmin_print_d906 (D906 *x);
	   void garmin_print_d1000 (D1000 *x);
	   void garmin_print_d1001 (D1001 *x);
	   void garmin_print_d1002 (D1002 *x);
	   void garmin_print_d1003 (D1003 *x);
	   void garmin_print_d1004 (D1004 *d);
	   void garmin_print_d1005 (D1005 *limits);
	   void garmin_print_d1006 (D1006 *x);
	   void garmin_print_d1007 (D1007 *x);
	   void garmin_print_d1008 (D1008 *w);
	   void garmin_print_d1009 (D1009 *x);
	   void garmin_print_d1010 (D1010 *x);
	   void garmin_print_d1011 (D1011 *x);
	   void garmin_print_d1012 (D1012 *x);
	   void garmin_print_d1013 (D1013 *x);
	   void garmin_print_d1015 (D1015 *x);

	private:
	   WAYPOINT waypoint;
	   WPCATEGORY wpcategory;
	   int route_header;
	   ROUTE route;
	   ROUTE_LINK route_link;
	   POINT point;
	   POINT_NODE *point_node;
	   TRACK track;
	   ALMANAC almanac;
	   DATETIME datetime;
	   FLIGHTBOOK flightbook;
	   radian_position_type rpt;
	   PVT pvt;
	   LAP lap;
	   LAP_NODE *lap_node;
	   RUN run;
	   RUN_NODE *run_node;
	   WORKOUT workout;
	   FITNESS fitness;
	   COURSE course;

	   double totalDistance;	// Distance in meters
	   long totalTime;		// Time in seconds
	   long pauseTime;		// Pause in seconds
	   double avgHR;		// Heart rate in beats per minute
	   double avgSpeed;		// Speed in km per hour
	   double maxSpeed;		// Speed in km per hour
	   int avgCadence;		// Cadence
	   double ascend;		// Height in meters
	   double descend;		// Height (downhill) in meters
};

#endif
